package server;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.sql.*;
import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: sam
 * Date: 25/06/12
 * Time: 19:44
 * To change this template use File | Settings | File Templates.
 */

public class LoginServlet extends MFHttpServlet {

    String UPLOAD_LOCATION = "/home/sam/mf_server_dump/music_finder_uploads"+File.separator;
    private StringBuilder strResp;
    private int numUploads = 0; //OUCH!!! Only bit of domain/meta data we store at class level... hack
    private Connection connection;
    private Document requestXML;
    private Properties props;

    public LoginServlet(){

    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        System.out.println("LoginServlet.doPost()"+"\n");

        connection = (Connection) getServletContext().getAttribute("db_connection");
        props = (Properties) getServletContext().getAttribute("properties");
        requestXML = (Document) request.getAttribute("request_xml");

        doLoginUser(request, response);

        connection = null;
    }

    public void doLoginUser(HttpServletRequest request, HttpServletResponse response){

        System.out.println("doLoginUser()");

        /*
        <?xml version="1.0" encoding="ISO-8859-1"?>
        <MFRequest>
            <Request type='Login' data=''/>
            <Login username='sam' password='test123'/>
        </MFRequest>
         */

        NodeList nList = requestXML.getElementsByTagName("Login");
        Node nNode = nList.item(0);
        Element eElement = (Element) nNode;
        String username = eElement.getAttribute("username");
        String password = eElement.getAttribute("password");
        String repository = eElement.getAttribute("respository");

        // null if result-set not matched from user details

        Map<String, String> loginData = getUserLoginDetails(username, password, repository);
        System.out.println("loginData.size() "+loginData.values().toString());

        if(loginData.size() == 0) {
            writeErrorResponse(request, response, "MF_USER_NOT_FOUND");
            //return;
        }else {

            HttpSession session = request.getSession();  // dont need (false), because we always want to log a valid user in!

            /*****************************************/
            /*****************************************/
            /*********** SET SESSION DATA ************/
            /*****************************************/
            /*****************************************/

            // Session data is non sensitive information.
            // Designed to alleviate DB calls / overhead
            // and provide easy access regularly needed info

            int userID = Integer.parseInt(loginData.get("userID").toString());
            String userEmail = loginData.get("userEmail").toString();
            int userRepository = Integer.parseInt(loginData.get("userRepository").toString());

            System.out.println("********************");
            System.out.println("SETTING SESSION DATA");
            System.out.println("********************");
            System.out.println("username "+username);
            System.out.println("userID "+userID);
            System.out.println("userEmail "+userEmail);
            System.out.println("userRepository "+userRepository);

            session.setAttribute("username", username);
            session.setAttribute("userID", userID);
            //session.setAttribute("userEmail", userEmail);
            session.setAttribute("userRepository", userRepository);

            StringBuilder genresListOnly = new StringBuilder(getGenres(userRepository).toString());
            StringBuilder userSettingsOnly = new StringBuilder(getUserSettings(userID).toString());

            StringBuilder strResp = new StringBuilder();
            strResp.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
            strResp.append("<MFResponse>\n");
            strResp.append("<Response type='Login'>\n");
            strResp.append("<Login name='"+username+"' session='"+session.getId()+"'/>\n");
            //strResp.append("<Genres>\n");
            strResp.append(genresListOnly.toString()+"\n");
            //strResp.append("</Genres>\n");
            strResp.append(userSettingsOnly.toString()+"\n");
            strResp.append("</Response>\n");
            strResp.append("</MFResponse>\n");

            response.setHeader("MFServer-Error", "false");

            write(response, strResp);
        }
    }




    // IMPORTANT >>>>>>>>>>>>> must only be called for login in, once.
    // this sets session data and does NOT use (false) arg, so will always create new
    // session, and hence cannot be used to check if user logged in
    private Map<String, String> getUserLoginDetails(String username, String password, String repository) {

        System.out.println("getUserLoginDetails()");

        // username must be unique within repository!!!!!!!!!!!!!!!!
        // when user logs in, we dont have userID yet. so we must have unique constraint on username, password & repository

        String userID = "";
        String userEmail = "";
        String userRepository = "";

        try {
            //Class.forName("com.mysql.jdbc.Driver");  //registering the jdbc driver here

            //db_con = DriverManager.getConnection(db_url, db_user, db_pwd);

            /**
             If you have a variable that comes from user input, it's essential that you use
             the ? rather than concatenating the strings. Users might enter a string maliciously,
             and if you drop the string straight into SQL it can run a command you didn't intend.
             If you are calling stored procedures that have been loaded onto your SQL server then use CallableStatement.
             */

            // int intUserID = 1;   NOT Integer userID, otherwise param isnt replaced
            // java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).

            String query = props.getProperty("music-alms.sql.login");

            PreparedStatement ps = connection.prepareStatement(query);

            //PreparedStatement ps = connection.prepareStatement(props.getProperty("music-alms.sql.login"));

            ps.setString(1, username);
            ps.setString(2, password);
            ps.setString(3, repository);

            ResultSet db_rs = ps.executeQuery();

            while (db_rs.next()) {  // if (rs.next()) {

                userID = db_rs.getString(1);
                userEmail = db_rs.getString(2);
                userRepository = db_rs.getString(3);
            }

            Map<String, String> hm = new HashMap<String, String>();

            if(!userID.equals("") && !userEmail.equals("") && !userRepository.equals(""))  {

                hm.put("userID", userID);
                hm.put("userEmail", userEmail);
                hm.put("userRepository", userRepository);
            }

            System.out.println("done music-alms.sql.login "+hm.toString());

            return hm;

        }
            /*catch(ClassNotFoundException e1) {

                System.out.println(e1.getMessage());
                e1.printStackTrace();
            }*/
        catch (SQLException e2) {

            System.out.println(e2.getMessage());
            e2.printStackTrace();
        }

        return null;
    }
}
